import argparse
import os
import threading
from concurrent.futures import ThreadPoolExecutor
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
import seaborn as sns

from model.powerModel.Pixel_13_latest import Pixel_13_latest
from model.powerModel.Pixel_14 import Pixel_14
from model.powerModel.Pixel import Pixel
from tools.timeDrainPlot.TimeDrainPlot import TimeDrainPlot


class BatteryParser:
    def __init__(self, output_path, data_path):
        self.global_network_data = {"wifi": {}}
        self.lock = threading.Lock()
        self.output_path = output_path
        self.pd_data = pd.DataFrame(columns=['环境',
                                             '序号',
                                             '策略',
                                             '平均电流',
                                             'Alarm唤醒CPU次数(Count/h)',
                                             'CPU平均运行时间(s/h)',
                                             '所有唤醒CPU原因(Count/h)',
                                             'CPU平均唤醒次数(Count/h)',
                                             'WIFI唤醒次数(Count/h)',
                                             'Audio(Count/h)',
                                             'Vibrator(Count/h)',
                                             "Ble_Scan"])

        self.networks = ["wifi"]
        self.strategies_list = ["fullAlign", "origin", 'simpty']
        self.data_path = data_path
        self.timeDrainPlot = TimeDrainPlot()

        for n in self.networks:
            tmp = {}
            for s in self.strategies_list:
                tmp[s] = {"rtc_alarm": [], "drain": []}
            self.global_network_data[n] = tmp
        self.stratgies = {
            "fullAlign": {"rtc_alarm": [], "drain": []},
            "origin": {"rtc_alarm": [], "drain": []},
            "simpty": {"rtc_alarm": [], "drain": []}
        }

        self.all_attri_num = pd.DataFrame()

    def start_process(self, version):
        futures = []
        # 可选参数flight 、 wifi 、lte
        for network_pattern in self.networks:
            # fullAlign对应完整的预测模块，align对应部分预测模块，paper对应对比论文，origin对应原生
            fullAlign_path = os.path.join(self.data_path, network_pattern, self.strategies_list[0])
            origin_path = os.path.join(self.data_path, network_pattern, self.strategies_list[1])
            simpty_path = os.path.join(self.data_path, network_pattern, self.strategies_list[2])
            # align_path = "batteryStats/fullAlign"
            # origin_path = "batteryStats/origin"
            stategies_path = [fullAlign_path, origin_path, simpty_path]
            for i in range(len(self.strategies_list)):
                print("\n" + self.strategies_list[i])
                with ThreadPoolExecutor(max_workers=36) as executor:
                    for file_name in os.listdir(stategies_path[i]):
                        print(file_name)
                        file_path = os.path.join(stategies_path[i], file_name)
                        # future = executor.submit(self.process_file, file_path, network_pattern, self.strategies_list[i],
                        #                          version, self.strategies_list[i])
                        self.process_file(file_path, network_pattern, self.strategies_list[i],
                                          version = version, policy= self.strategies_list[i])
                        # futures.append(future)

    def get_hardware_element(self, battery):
        hardware = pd.DataFrame()
        hardware['cpu_runtime'] = [battery.cpu_runtime.total_seconds() / battery.testTime]
        hardware['wifi_radio'] = [battery.radio_count]
        hardware['rtc_alarm'] = [battery.qpnpRtcAlarm / battery.testTime]
        hardware['delivery_alarm'] = [battery.deliveryRtcAlarm / battery.testTime]
        hardware['wakeup_reason'] = [battery.wakeup_reason / battery.testTime]
        hardware['wlan_ce'] = [battery.wlan_ce_2 / battery.testTime]
        hardware['wlan_ce_rtc_alarm'] = [(battery.wlan_ce_2 + battery.qpnpRtcAlarm) / battery.testTime]
        hardware['drain'] = [battery.averageDrain]
        return hardware

    def add_data(self, con, metric):
        if metric == "wlan_ce":
            return

    def get_stategy_element(self, ):
        pass

    # 使用箱型图的方法去除异常值
    def remove_outliers(self, data):
        q1 = np.percentile(data, 25)
        q3 = np.percentile(data, 75)
        iqr = q3 - q1
        lower_bound = q1 - 1.5 * iqr
        upper_bound = q3 + 1.5 * iqr
        filtered_data = [x for x in data if lower_bound <= x <= upper_bound]
        return filtered_data

    def calculate_stats(self, arr):
        mean = np.mean(arr)
        std = np.std(arr)
        median = np.median(arr)
        return mean, std, median

    def print_stats(self, metrics):
        for j in range(len(self.networks)):
            align_drain = self.global_network_data.get(self.networks[j]).get(self.strategies_list[0]).get(metrics)
            origin_drain = self.global_network_data.get(self.networks[j]).get(self.strategies_list[1]).get(metrics)
            simpty_drain = self.global_network_data.get(self.networks[j]).get(self.strategies_list[2]).get(metrics)
            align_drain = self.remove_outliers(align_drain)
            origin_drain = self.remove_outliers(origin_drain)
            mean, std, median = self.calculate_stats(align_drain)
            print("\n" + self.networks[j])
            print("Align")
            print(f'电流平均值: {mean}')
            print(f'电流标准差: {std}')
            print(f'电流中位数: {median}')
            origin_mean, origin_std, origin_median = self.calculate_stats(origin_drain)
            print("Origin")
            m = -(origin_mean - mean) / origin_mean * 100
            n = -(origin_std - std) / origin_std * 100
            q = -(origin_median - median) / origin_median * 100
            print(f'电流平均值: {origin_mean}')
            print(f'电流标准差: {origin_std}')
            print(f'电流中位数: {origin_median}')

            # simpty
            print(f'\nours电流下降比例: {m}%')
            print(f'ours电流下降比例: {n}%')
            print(f'ours电流下降比例: {q}%')

    def plot_stategy_pic(self):
        attri = ["rtc_alarm", "drain"]
        # 创建一个2行2列的子图
        fig, axs = plt.subplots(1, len(attri) * len(self.networks))
        for i in range(len(attri)):
            for j in range(len(self.networks)):
                axs[i].boxplot(
                    [self.global_network_data.get(self.networks[j]).get(self.strategies_list[0]).get(attri[i]),
                     self.global_network_data.get(self.networks[j]).get(self.strategies_list[1]).get(attri[i])],
                    showmeans=True,
                    meanline=True)
                axs[i].set_xticklabels([self.strategies_list[0], self.strategies_list[1]])
                axs[i].set_title(self.networks[j] + " " + attri[i])
        # 调整子图之间的垂直间距
        plt.subplots_adjust(hspace=0.5)
        # 显示图形
        plt.show()

    def plot_time_drain(self):
        self.timeDrainPlot.plot()

    def analyse_corr(self, all_attri_num):
        corr_matrix = all_attri_num.corr()
        # 使用Seaborn绘制相关性系数的热图
        # 使用Seaborn绘制相关性系数的热图，旋转标签
        sns.heatmap(corr_matrix, annot=True, cmap="coolwarm", xticklabels=True, yticklabels=True, fmt=".2f",
                    cbar=False)

        # 设置图形标题
        plt.title('Correlation Matrix')
        # 显示图形
        plt.show()
        corr_qpnp_rtc_alarm = corr_matrix['drain'].drop('drain')
        print(corr_matrix['drain'])

    def process_file(self, file_path, network_pattern, strategy, version, policy):
        if int(version) == 13:
            battery = Pixel_13_latest(file_path, policy)
        else:
            battery = Pixel_14(file_path, policy)
        self.lock.acquire()
        print(file_path + ": ")
        battery.print_hardware()
        battery.print_drain()
        self.pd_data = pd.concat([self.pd_data, battery.all_to_pd()])
        # 添加数据
        self.global_network_data.get(network_pattern).get(strategy).get("rtc_alarm").append(
            battery.wlan_ce_2 / battery.testTime)
        self.global_network_data.get(network_pattern).get(strategy).get("drain").append(battery.averageDrain)
        self.timeDrainPlot.parseFile(battery,policy)
        self.lock.release()

    def to_csv(self):
        self.pd_data.to_csv(self.output_path, encoding="utf_8_sig", index=False)
